/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦]
 * 
 * https://zhiqim.org/project/zhiqim_framework/zhiqim_httpd.htm
 *
 * Zhiqim Httpd is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package org.zhiqim.httpd.nio;

import java.io.IOException;

import org.zhiqim.httpd.HttpInputStream;
import org.zhiqim.kernel.constants.CodeConstants;
import org.zhiqim.kernel.util.Asserts;
import org.zhiqim.kernel.util.Bytes;
import org.zhiqim.kernel.websocket.WebSocketPacket;

/**
 * HttpWebSocket异常数据格式：
 * 
 * 一共分5步读取数据
 * 1、读first字节
 * 2、读second字节
 * 3、根据len读2字节或8字节
 * 4、读maskingKey
 * 5、读data
 *
 * @version v1.0.0 @author zouzhigang 2017-6-1 新建与整理
 */
public class HttpNioWebSocketPacket extends WebSocketPacket implements CodeConstants
{
    private int step;
    private int first;
    private int second;
    private byte[] buffer;
    private int bufferOff;
    private int maskingKeyOff;
    private int dataOff;
    
    public boolean parse(HttpInputStream in) throws IOException
    {
        if (step < 1)
        {//第一步
            first = in.read();
            if (first == -1)
            {//异步未读完，等待下次再读
                return false;
            }
            
            step = 1;
        }
        
        if (step < 2)
        {//第二步
            second = in.read();
            if (second == -1)
            {//异步未读完，等待下次再读
                return false;
            }
            
            step = 2;
        }
        
        //1.fin
        fin = (first & 0x80) != 0;
        
        //2.opcode
        opcode = first & 0x0F;
        
        //3.mask
        mask = (second & 0x80) != 0;
        
        //4.len
        len = dataLen = second & 0x7F;
        if (isTwoLength())
        {
            if (step < 3)
            {
                if (buffer == null)
                {//初始化
                    buffer = new byte[2];
                    bufferOff = 0;
                }
                
                byte[] buf = in.read(2 - bufferOff);
                if (buf != null && buf.length > 0)
                {
                    bufferOff = Bytes.putBytes(buffer, bufferOff, buf);
                }
                
                if (bufferOff < 2)
                {//异步未读完，等待下次再读
                    return false;
                }
                
                dataLen = Bytes.BU.getShortUnsigned(buffer, 0);
                step = 3;
            }
        }
        else if (isEightLength())
        {
            if (step < 3)
            {
                if (buffer == null)
                {//初始化
                    buffer = new byte[8];
                    bufferOff = 0;
                }
                
                byte[] buf = in.read(8 - bufferOff);
                if (buf != null && buf.length > 0)
                {
                    bufferOff = Bytes.putBytes(buffer, bufferOff, buf);
                }
                
                if (bufferOff < 8)
                {//异步未读完，等待下次再读
                    return false;
                }
                
                long length = Bytes.BU.getLong(buf, 0);
                if (length > Integer.MAX_VALUE)
                    throw Asserts.exception("超出支持的能力");
                
                dataLen = (int)length;
                step = 3;
            }
        }
        
        if (step < 4)
        {//5.maskingkey
            if (mask)
            {
                if (maskingKey == null)
                {//初始化
                    maskingKey = new byte[4];
                    maskingKeyOff = 0;
                }
                
                byte[] buf = in.read(4 - maskingKeyOff);
                if (buf != null && buf.length > 0)
                {
                    maskingKeyOff = Bytes.putBytes(maskingKey, maskingKeyOff, buf);
                }
                
                if (maskingKeyOff < 4)
                {//异步未读完，等待下次再读
                    return false;
                }
            }
            
            step = 4;
        }
        
        if (step < 5)
        {//6.data
            if (dataLen > 0)
            {//有内容
                if (data == null)
                {//初始化
                    data = new byte[dataLen];
                    dataOff = 0;
                }
                
                byte[] buf = in.read(dataLen - dataOff);
                if (buf != null && buf.length > 0)
                {
                    dataOff = Bytes.putBytes(data, dataOff, buf);
                }
                
                if (dataOff < dataLen)
                {//异步未读完，等待下次再读
                    return false;
                }
                
                if (mask)
                {
                    for (int i=0;i<dataLen;i++)
                    {
                        data[i] = (byte)(data[i] ^ maskingKey[i % 4]);
                    }
                }
            }
            
            step = 5;
        }

        return true;
    }
    
    /***********************************************************************/
    // 获取&设置
    /***********************************************************************/
    
    public boolean isParsed()
    {
        return step == 5;
    }
}
